﻿/*
 * Copyright (c) 2008 黑色珊瑚::Tsorgy.Utils, Reserved.
 * 
 * Filename:    @(#)DragPictureBox.cs
 * Create by:   TsOrgY
 * Email:       tsorgy@gmail.com
 * Date:        2008/12/24 0:27:04
 * 
 * Classname:   DragPictureBox
 * Description: 可拖动图片的图片框
 *              
 */

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.IO;

namespace Walson.Walson.Form
{

    /// <summary>
    /// 加载瓦片地图的图片框.
    /// </summary>
    [DefaultProperty("Image")]
    public class MapGridBox : PictureBox
    {

        #region 私有成员
        // 当前图像显示坐标.
        private int _x, _y;
        // 临时偏移量.
        private int t_x, t_y;
        // 光标
        private static Cursor _cursorHandClick, _cursorHand;

        private Image _image;

        // 处于中心的瓦片的 XY 编号
        private Point _centerTIleXY;
        // 处于中心的瓦片的经纬度坐标
        private PointF _centerTIleCoor;
        // 地图的偏移量
        private Point _offsetXY;

        
        #endregion 私有成员       



        #region 公开属性

        /// <summary>
        /// 地图中心位置的瓦片编号
        /// </summary>
        public Point CenterTile
        {
            get;
            set;
        }

        /// <summary>
        /// 地图数据库的位置
        /// </summary>
        public string DatabaseLocation
        {
            get;
            set;
        }

        /// <summary>
        /// 地图数据的存放位置
        /// </summary>
        public string MapFolder
        {
            get;
            set;
        }

        /// <summary>
        /// 地图的级别
        /// </summary>
        public int Level
        {
            get;
            set;
        }

        public Size MapTileSize
        {
            get;
            set;
        }

        /// <summary>
        /// 获取或设置显示在 <see cref="Tsorgy.Utils.DragPictureBox"/> 上的图片.
        /// </summary>
        [Category("Appearance")]
        [Description("显示在 DragPictureBox 上的图片")]
        [Localizable(true)]
        [DefaultValue(null)]
        public new Image Image
        {
            get { return _image; }
            set
            {
                _image = value;
                _x = (this.Width - _image.Width) / 2;
                _y = (this.Height - _image.Height) / 2;
                GC.Collect();
                this.Invalidate();
            }
        }

        [Category("Appearance")]
        [Description("显示在 MapGrid 上的文本")]
        [Localizable(true)]
        [DefaultValue(null)]
        public new string Text
        {
            get;
            set;
        }

        [Category("Appearance")]
        [Description("显示在 MapGrid 上文本的颜色")]
        [Localizable(true)]
        [DefaultValue(null)]
        public new Color ForeColor
        {
            get;
            set;
        }

        [Category("Appearance")]
        [Description("显示在 MapGrid 上文本的背景颜色")]
        [Localizable(true)]
        [DefaultValue(null)]
        public Color TextBackColor
        {
            get;
            set;
        }

        [Category("Appearance")]
        [Description("显示在 MapGrid 上文本的字体")]
        [Localizable(true)]
        [DefaultValue(null)]
        public new Font Font
        {
            get;
            set;
        }

        private Point _CursorPositionOnMap=new Point();
        /// <summary>
        /// 当前鼠标在当前地图可是区域内的坐标
        /// </summary>
        public Point CursorPositionOnMap
        {
            get
            {
                return _CursorPositionOnMap;
            }
            private set
            {
                _CursorPositionOnMap = value;
            }
        }

        #endregion 公开属性



        #region 公开方法

        /// <summary>
        /// 刷新地图
        /// </summary>
        public new void Update()
        {

        }

        /// <summary>
        /// 移动地图
        /// </summary>
        /// <param name="x">X 方向偏移</param>
        /// <param name="y">Y 方向偏移</param>
        public void MoveMap(int x,int y)
        {
            if (x * y == 0)
                return;

            _x += x;
            _y += y;
            _CurrentX = this.Width / 2;
            _CurrentY = this.Height / 2;
            if (MapMoved != null)
                onMapMoved(x, y);
            this.Invalidate();
        }

        #endregion 公开方法

        #region 事件

        public class BorderExceedEventArg
        {
            /// <summary>
            /// 超界的边
            /// </summary>
            [Flags] 
            public enum BorderSide
            {
                /// <summary>
                /// 没有超界
                /// </summary>
                None=0,
                /// <summary>
                /// 左边界
                /// </summary>
                Left = 1, 
                /// <summary>
                /// 右边界
                /// </summary>
                Right = 2,
                /// <summary>
                /// 上边界
                /// </summary>
                Top = 4, 
                /// <summary>
                /// 下边界
                /// </summary>
                Bottom = 8 
            };

            /// <summary>
            /// 超界的边
            /// </summary>
            public BorderSide ExceedSide
            {
                get;
                set;
            }

            public BorderExceedEventArg(BorderSide side)
            {
                ExceedSide = side;
            }

            public BorderExceedEventArg()
            {
                ExceedSide = 0;
            }
        }

        public delegate void BorderExceddedHandler(object sender,BorderExceedEventArg e);
        public event BorderExceddedHandler BorderExceeded;
        protected void onBorderExceeded(BorderExceedEventArg e)
        {
            if (BorderExceeded != null)
            {
                BorderExceeded(this, e);
            }
        }

        public struct DistanceInfo
        {
            public Point StartPoint;
            public int DistanceX;
            public int DistanceY;
        }
        public delegate void MapMovedHandler(object sender, DistanceInfo Distance);
        public event MapMovedHandler MapMoved;
        protected void onMapMoved(int x, int y)
        {
            if (MapMoved != null)
            {
                DistanceInfo distance = new DistanceInfo();
                distance.StartPoint = new Point(_CurrentX, _CurrentY);
                distance.DistanceX = x;
                distance.DistanceY = y;
                MapMoved(this, distance);
            }
        }

        
        public event MouseEventHandler MouseWheel;
        protected override void OnMouseWheel(MouseEventArgs e)
        {
            //base.OnMouseWheel(e);
            if (MouseWheel != null)
                MouseWheel(this, e);
        }

        #endregion



        /// <summary>
        /// 计算地图需要多少个瓦片
        /// </summary>
        /// <returns></returns>
        private Size CalculateMapGrid(int offsetX,int offsetY)
        {
            int RowCount, LineCount;
            RowCount = this.Width / 256 + 2;
            LineCount = this.Height / 256 + 2;
            return new Size(RowCount, LineCount);
        }

        /// <summary>
        /// 初始化 <see cref="Tsorgy.Utils.DragPictureBox"/> 类的新实例.
        /// </summary>
        public MapGridBox()
            : base()
        {
            _image = null;
            // 设置双缓冲.
            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true);

            Assembly _assembly;
            Stream _imageStream;

            if (MapTileSize == null)
                MapTileSize = new Size(256, 256);

            this.MouseWheel += new MouseEventHandler(MapGridBox_MouseWheel);
            this.PreviewKeyDown += new PreviewKeyDownEventHandler(MapGridBox_PreviewKeyDown);
            _assembly = Assembly.GetExecutingAssembly();
            _imageStream = _assembly.GetManifestResourceStream("Walson.Walson.Form.MapGridBox.Resources.Hand.ico");
            _cursorHand = (new Cursor(_imageStream));
            _imageStream = _assembly.GetManifestResourceStream("Walson.Walson.Form.MapGridBox.Resources.HandClick.ico");
            _cursorHandClick = (new Cursor(_imageStream));
            this.ForeColor = SystemColors.WindowText;
            this.TextBackColor = Color.FromArgb(100, 255, 255, 255);
            this.Font = SystemFonts.DefaultFont;
            this.BackColor = Color.FromArgb(229, 227, 223);
            GC.Collect();
        }

        void MapGridBox_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
        {
            if (e.KeyCode == Keys.Left)
            {
                MoveMap(-10, 0);
            }
            else if (e.KeyCode == Keys.Right)
            {
                MoveMap(10, 0);
            }
            else if (e.KeyCode == Keys.Up)
            {
                MoveMap(0, -10);
            }
            else if (e.KeyCode == Keys.Down)
            {
                MoveMap(0, 10);
            }
        }

        void MapGridBox_MouseWheel(object sender, MouseEventArgs e)
        {
            base.OnMouseWheel(e);
            //throw new NotImplementedException();
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (_image != null)
            {
                _x = (this.Width - _image.Width) / 2;
                _y = (this.Height - _image.Height) / 2;
                this.Invalidate();
            }
        }

        /// <summary>
        /// 引发 <see cref="E:System.Windows.Forms.Control.Paint"></see> 事件.
        /// </summary>
        /// <param >包含事件数据的 <see cref="T:System.Windows.Forms.PaintEventArgs"></see>.</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (_image != null)
            {
                Graphics g = e.Graphics;
                g.Clear(this.BackColor);
// 
//                 int offsetx, offsety;
// 
//                 
                g.DrawImage(_image,new Rectangle(0,0,this.Width,this.Height),new Rectangle(0-_x,0-_y,this.Width,this.Height),GraphicsUnit.Pixel);

                if (this.Text != null)
                {
                    SizeF bgSize=g.MeasureString(this.Text, this.Font);
                    Size bgSize2 = new Size(this.Width - 30, (int)bgSize.Height + 1);
                    //bgSize2.Height = (int)bgSize.Height + 1;
                    //bgSize2.Width = (int)bgSize.Width + 1;
                    g.FillRectangle(new SolidBrush(this.TextBackColor), new Rectangle(new Point(10, 10), bgSize2));
                    g.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), 10, 10);
                    
                }
                


                //g.DrawImage(_image, _x, _y, _image.Width, _image.Height);
                //g.DrawImage(_image, _x, _y,);
            }
        }

        /// <summary>
        /// 引发 <see cref="E:System.Windows.Forms.Control.MouseMove"></see> 事件.
        /// </summary>
        /// <param >包含事件数据的 <see cref="T:System.Windows.Forms.MouseEventArgs"></see>.</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {

            base.OnMouseMove(e);
            _CursorPositionOnMap.X =  e.X;
            _CursorPositionOnMap.Y =  e.Y;
            this.Focus();
            if (_image != null && e.Button == MouseButtons.Left)
            {
                _x = e.X - t_x;
                _y = e.Y - t_y;
                

                BorderExceedEventArg e0 = new BorderExceedEventArg();
                // 如果图片拖出边缘.
                if (_x > 0)
                    e0.ExceedSide |=  BorderExceedEventArg.BorderSide.Left;
                else if (_x < this.Width - _image.Width)
                    e0.ExceedSide |= BorderExceedEventArg.BorderSide.Right;
                if (_y > 0)
                    e0.ExceedSide |= BorderExceedEventArg.BorderSide.Top;
                else if (_y < this.Height - _image.Height)
                    e0.ExceedSide |= BorderExceedEventArg.BorderSide.Bottom;
                // 重绘.
                this.Invalidate(false);
                if (e0.ExceedSide != BorderExceedEventArg.BorderSide.None)
                    onBorderExceeded(e0);
                //onMapMoved(e.X - _CurrentX, e.Y - _CurrentY);
            }
        }

        int _CurrentX, _CurrentY;
        /// <summary>
        /// 引发 <see cref="E:System.Windows.Forms.Control.MouseDown"></see> 事件.
        /// </summary>
        /// <param >包含事件数据的 <see cref="T:System.Windows.Forms.MouseEventArgs"></see>.</param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            _CurrentX = e.X;
            _CurrentY = e.Y;
            base.OnMouseDown(e);
            if (_image != null)
            {
                t_x = e.X - _x;
                t_y = e.Y - _y;
            }
            this.Cursor = _cursorHandClick;
        }

        /// <summary>
        /// 引发 <see cref="E:System.Windows.Forms.Control.MouseUp"></see> 事件.
        /// </summary>
        /// <param name="e">包含事件数据的 <see cref="T:System.Windows.Forms.MouseEventArgs"></see>.</param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            this.Cursor = _cursorHand;
            if (e.X - _CurrentX != 0 || e.Y - _CurrentY != 0)
            {
                onMapMoved(e.X - _CurrentX, e.Y - _CurrentY);
                this.Invalidate();
            }

        }
    }
}